#include "MsgHandler/include/JsonHandler.h"

static const int BLOCK_SIZE=256;

JsonStrategy* JsonStrategyFactory::createStrategy(const std::string& type)
{

	if (type == "login")
	{
        return new LoginStrategy();
	}
	else if (type == "getuserinfo")
	{
        return new GetUserInfoStrategy();
	}
	else if (type == "getcontactlist")
	{
        return new GetContactListStrategy();
	}
    else if(type=="getfriendchat")
    {
        return new GetFriendChatStrategy();
    }
    else if(type=="getchattmp")
    {
        return new GetChatTmpStrategy();
    }
	else if (type == "csmessage")
	{
        return new CsMessageStrategy();
	}
    else if(type=="getfriendinfo")
    {
        return new GetFriendInfoStrategy();
    }
    else if(type=="getfriendapplylist")
    {
        return new GetFriendApplyListStrategy();
    }
    else if(type=="getfriendapplytmp")
    {
        return new  GetFriendApplyTmpStrategy();
    }
    else if(type=="getfriendavatarupdate")
    {
        return new  GetFriendAvatarTmpStrategy();
    }
    else if(type=="getocupdate")
    {
        return new GetOCUpdateStrategy();
    }
    else if(type=="getnameupdate")
    {
        return new GetNameUpdateStrategy();
    }
    else if(type=="getfriendlist")
    {
        return new GetFriendListStrategy();
    }
	else if (type == "friendapply")
	{
        return new FriendApplyStrategy();
	}
    else if (type == "friendapplyaccess")
	{
        return new FriendApplyPassStrategy();
	}
	else if (type == "updateuseroc")
	{
        return new UpdateUserOCStrategy();
	}
	else if (type == "updateusername")
	{
        return new UpdateUserNameStrategy();
    }
    else if(type=="addtofriendlist")
    {
        return new AddToFriendListStrategy();
    }
	else
	{
		return nullptr;
	}
}

void LoginStrategy::execute(const int socket,const rapidjson::Document* content) const
{
    if(content->HasParseError())
    {
        std::cout<<"Doc has error : "<<content->GetParseError()<<std::endl;
        delete content;
        return;
    }
    //获取用户名和密码
    if(content->HasMember("useroc")&&content->HasMember("password"))
    {
        std::string useroc=(*content)["useroc"].GetString();
        std::string password=(*content)["password"].GetString();
        //从数据库连接池中获取连接
        auto user_conn_set=SqlSetManager::getInstance()->getSet("user");
        auto conn=user_conn_set->acquire();


        //查询
        std::vector<std::string> value={useroc};
        auto res=conn->preExecute("SELECT passwd,user_status FROM userinfo WHERE useroc=?",value);

        std::string response;
        if(!conn->resIsEmpty()) //不使用while原因：useroc为主键，不存在多条结果
        {
            if(res->next())
            {
            //从数据库中获取的用户密码
            std::string db_passwd=res->getString(1);
            //std::cout<<"user password -> "<<db_passwd<<std::endl;
            //数据库中用户状态
            char status=res->getString(2)[0];
            //std::cout<<"user status -> "<<status<<std::endl;

            //开始构造响应报文
            if(db_passwd==password)
            {
                if(status=='0')
                {
                    //发送成功报文
                    JsonEncoder::getInstance().loginJson(response,LogInType::PASS);
                    //设置用户在线
                    //添加socket维护表
                    SocketManager::getInstacne()->addSocket(useroc,socket);

                }
                else
                {
                    //禁止
                    JsonEncoder::getInstance().loginJson(response,LogInType::BAN);
                }
            }
            else
            {
                //错误
                JsonEncoder::getInstance().loginJson(response,LogInType::ERROR);
            }
        }

        }
        else
        {

            //错误
            JsonEncoder::getInstance().loginJson(response,LogInType::ERROR);
        }

        //std::cout<<response<<std::endl;
        //发送报文
        TcpServer::sendMsg(socket,response);
        //归还连接给线程池
        user_conn_set->release(conn);
        delete content;
    }
}

void GetUserInfoStrategy::execute(const int socket,const rapidjson::Document* content) const
{
    //std::cout<<"GetUserInfo"<<std::endl;
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("useroc"))
    {

        std::string useroc=(*content)["useroc"].GetString();
        //std::cout<<"useroc->"<<useroc<<"<-"<<std::endl;
        auto conn_set=SqlSetManager::getInstance()->getSet("user");
        auto conn=conn_set->acquire();
        std::vector<std::string> value={useroc};
        //查找用户信息
        auto res=conn->preExecute("SELECT user_name,avatar_path FROM userinfo WHERE useroc=?",value);
        if(!conn->resIsEmpty())
        {
            //有结果
            if(res->next())
            {
                std::string  name=res->getString(1);
                std::string avatar_path=res->getString(2);


                MsgVector userinfo;
                userinfo.createHead("userinfo");
                userinfo.addContent(name.c_str(),false);

                int pre_len=userinfo.length();
                std::ifstream ios(avatar_path,std::ios::binary);
                if(!ios)
                {
                    std::cout<<"open file failed"<<std::endl;
                    conn_set->release(conn);
                    return;
                }
                ios.seekg(0,std::ios::end);
                std::streamsize file_size=ios.tellg();
                ios.seekg(0,std::ios::beg);
                int read_done=0;
                int block_size=BLOCK_SIZE;

                userinfo.resize(pre_len+file_size+1);


                while(read_done<file_size)
                {
                    if(file_size-read_done<block_size)
                    {
                        block_size=file_size-read_done;
                    }
                    ios.read(userinfo[read_done+pre_len],block_size);
                    read_done+=block_size;
                }

                auto res_str=userinfo.getMsg();
                TcpServer::sendMsg(socket,*res_str);
                delete res_str;
                conn_set->release(conn);
            }

        }
        //无查询结果
        else
        {
            conn_set->release(conn);
        }
        delete content;
    }

}

void GetContactListStrategy::execute(const int socket,const rapidjson::Document* content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("useroc"))
    {
        std::string useroc=(*content)["useroc"].GetString();
        std::string db_name=OCDatabaseMapper::getInstance()->getDB(useroc);


        //执行更新操作
        auto conn_set=SqlSetManager::getInstance()->getSet("user");
        auto conn=conn_set->acquire();
        auto conninfo_set=SqlSetManager::getInstance()->getSet("user");
        auto conninfo=conninfo_set->acquire();
        auto res=conn->preExecute("SELECT oldoc,newoc,targetoc FROM ocupdate WHERE targetoc=?",useroc);
        while(res->next())
        {
            std::string targetoc=res->getString(3);
            std::string oldoc=res->getString(1);
            std::string newoc=res->getString(2);

            auto target_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(targetoc));
            auto target_conn=target_conn_set->acquire();

            target_conn->executeVoid(fmt::format("ALTER TABLE {} RENAME TO {}",oldoc,newoc));

            target_conn->preExecuteVoid("UPDATE contactlist SET useroc=? WHERE useroc=?",newoc,oldoc);
            target_conn->preExecuteVoid("UPDATE friendlist SET friendoc=? WHERE friendoc=?",newoc,oldoc);
            target_conn->preExecuteVoid("UPDATE friendapply SET targetoc=? WHERE targetoc=?",newoc,oldoc);
            target_conn->preExecuteVoid("UPDATE friendapply_tmp SET targetoc=? WHERE targetoc=?",newoc,oldoc);
            target_conn->preExecuteVoid("UPDATE chat_tmp SET sender=? WHERE sender=?",newoc,oldoc);
            target_conn_set->release(target_conn);

            conninfo->preExecuteVoid("DELETE FROM nameupdate WHERE targetoc=?",useroc);
            conninfo->preExecuteVoid("DELETE FROM avatarupdate WHERE targetoc=?",useroc);

        }
        conn->preExecuteVoid("DELETE FROM ocupdate WHERE targetoc=?",useroc);



        std::string query=fmt::format("SELECT user.userinfo.useroc,user.userinfo.user_name,user.userinfo.avatar_path FROM user.userinfo\
                                      INNER JOIN {}.contactlist ON user.userinfo.useroc = {}.contactlist.useroc",db_name,db_name);
        res=conn->execute(query);
        if(!conn->resIsEmpty())
        {
            while(res->next())
            {
                std::string useroc=res->getString(1);
                std::string user_name=res->getString(2);
                std::string avatar_path=res->getString(3);

                MsgVector contactinfo;
                contactinfo.createHead("contactlist");
                contactinfo.addContent(useroc.c_str(),false);
                contactinfo.addContent(user_name.c_str(),false);
                int pre_len=contactinfo.length();
                std::ifstream ios(avatar_path,std::ios::binary);
                if(!ios)
                {
                    std::cout<<"open file failed"<<std::endl;
                    conn_set->release(conn);
                    return;
                }
                ios.seekg(0,std::ios::end);
                std::streamsize file_size=ios.tellg();
                ios.seekg(0,std::ios::beg);
                int read_done=0;
                int block_size=BLOCK_SIZE;

                contactinfo.resize(pre_len+file_size+1);


                while(read_done<file_size)
                {
                    if(file_size-read_done<block_size)
                    {
                        block_size=file_size-read_done;
                    }
                    ios.read(contactinfo[read_done+pre_len],block_size);
                    read_done+=block_size;
                }
                //contactinfo.addContent("abcdefghijklmn",true);
                auto res_str=contactinfo.getMsg();
                TcpServer::sendMsg(socket,*res_str);
                delete res_str;
            }


        }
        conn_set->release(conn);
    }
    MsgVector end;
    end.createHead("contactlistend");
    auto end_str=end.getMsg();
    TcpServer::sendMsg(socket,*end_str);
    delete end_str;
    delete content;
}
void GetFriendChatStrategy::execute(const int socket, const rapidjson::Document *content) const
{
    //std::cout<<"GetFriendChat"<<std::endl;
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("useroc"))
    {
        std::string useroc=(*content)["useroc"].GetString();
        auto conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));
        auto conn=conn_set->acquire();
        auto res=conn->execute("SELECT useroc FROM contactlist");
        while(res->next())
        {
            std::string oc=res->getString(1);

            std::string query=fmt::format("SELECT sender,content\
                                          FROM (\
                                          SELECT *\
                                          FROM {}\
                                          ORDER BY id DESC\
                                          LIMIT 60\
                                          )AS subquery\
                                          ORDER BY id ASC",oc);
            auto chat_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));

            auto chat_conn=chat_set->acquire();

            auto chat_res=chat_conn->execute(query);

            if(!chat_conn->resIsEmpty())
            {
                MsgVector chat;
                chat.createHead("friendchat");
                chat.addContent(oc.c_str(),false);
                while(chat_res->next())
                {
                    std::string sender=chat_res->getString(1);
                    std::string content=chat_res->getString(2);
                    chat.addContent(sender.c_str(),false);
                    chat.addContent(content.c_str(),false);
                }
                chat_set->release(chat_conn);

                chat.eraseBack(3);
                auto msg=chat.getMsg();
                TcpServer::sendMsg(socket,*msg);
                delete msg;
            }

        }
        conn_set->release(conn);

        MsgVector end;
        end.createHead("friendchatend");
        auto end_str=end.getMsg();
        TcpServer::sendMsg(socket,*end_str);
        //std::cout<<"send friendchatend"<<std::endl;
        delete end_str;


    }
}


void GetChatTmpStrategy::execute(const int socket, const rapidjson::Document *content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("useroc"))
    {
         std::string useroc=(*content)["useroc"].GetString();
         auto user_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));
         auto user_conn=user_conn_set->acquire();
         auto res=user_conn->execute("SELECT sender,content FROM chat_tmp");
         if(!user_conn->resIsEmpty())
         {
             MsgVector msg;
             msg.createHead("chattmp");
             while(res->next())
             {
                 std::string sender=res->getString(1);
                 std::string content=res->getString(2);
                 msg.addContent(sender.c_str(),false);
                 msg.addContent(content.c_str(),false);
             }
             msg.eraseBack(3);
             auto chat_tmp=msg.getMsg();
             TcpServer::sendMsg(socket,*chat_tmp);
             delete chat_tmp;

             //重置游标到首行
             user_conn->resetResPos();
             user_conn->startTransaction();
             while(res->next())
             {
                 std::string sender=res->getString(1);
                 std::string content=res->getString(2);
                 std::string query=fmt::format("INSERT INTO {}(sender,content) VALUES('1',?)",sender);
                 user_conn->preExecuteVoid(query,content);

             }
             user_conn->commit();
             user_conn->preExecuteVoid("TRUNCATE TABLE chat_tmp");
             user_conn_set->release(user_conn);
         }

    }
    MsgVector end;
    end.createHead("chattmpend");

    auto end_str=end.getMsg();
    TcpServer::sendMsg(socket,*end_str);
    delete end_str;
    delete content;
}

void GetFriendApplyListStrategy::execute(const int socket, const rapidjson::Document *content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("useroc"))
    {
        std::string useroc=(*content)["useroc"].GetString();
        auto user_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));
        auto user_conn=user_conn_set->acquire();

        user_conn->startTransaction();
        user_conn->executeVoid("INSERT INTO friendapply SELECT * FROM friendapply_tmp");
        user_conn->executeVoid("TRUNCATE TABLE friendapply_tmp");
        user_conn->commit();

        auto res=user_conn->execute("SELECT user.userinfo.useroc,user.userinfo.user_name,friendapply.apply_status,user.userinfo.avatar_path FROM user.userinfo INNER JOIN friendapply ON user.userinfo.useroc = friendapply.targetoc");
        while(res->next())
        {
            std::string targetoc=res->getString(1);
            std::string target_name=res->getString(2);
            std::string status=res->getString(3);
            std::string avatar=res->getString(4);

            MsgVector msg;
            msg.createHead("friendapplylist");
            msg.addContent(targetoc.c_str(),false);
            msg.addContent(target_name.c_str(),false);
            msg.addContent(status.c_str(),false);
            int pre_len=msg.length();
            std::ifstream ios(avatar,std::ios::binary);
            if(!ios)
            {
                std::cout<<"open file failed"<<std::endl;
                user_conn_set->release(user_conn);
                return;
            }
            ios.seekg(0,std::ios::end);
            std::streamsize file_size=ios.tellg();
            ios.seekg(0,std::ios::beg);
            int read_done=0;
            int block_size=BLOCK_SIZE;

            msg.resize(pre_len+file_size+1);


            while(read_done<file_size)
            {
                if(file_size-read_done<block_size)
                {
                    block_size=file_size-read_done;
                }

                ios.read(msg[read_done+pre_len],block_size);
                read_done+=block_size;
            }

            auto str=msg.getMsg();
            TcpServer::sendMsg(socket,*str);
            delete str;
        }
        user_conn_set->release(user_conn);
        MsgVector end;
        end.createHead("friendapplylistend");
        auto end_str=end.getMsg();
        TcpServer::sendMsg(socket,*end_str);
        delete end_str;
    }
    delete content;
}

void CsMessageStrategy::execute(const int socket,const rapidjson::Document* content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("targetoc")&&content->HasMember("useroc")&&content->HasMember("message"))
    {
        std::string targetoc=(*content)["targetoc"].GetString();
        std::string useroc=(*content)["useroc"].GetString();
        std::string message=(*content)["message"].GetString();

        auto target_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(targetoc));
        auto target_conn=target_conn_set->acquire();

        auto user_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));
        auto user_conn=user_conn_set->acquire();

        //若用户在线则转发,并同步到数据库中
        if(SocketManager::getInstacne()->isAlive(targetoc))
        {
            std::string response;
            JsonEncoder::getInstance().sendMsg(response,message,useroc);

            int target_socket=SocketManager::getInstacne()->getSocket(targetoc);
            TcpServer::sendMsg(target_socket,response);


            //为双方记录表添加消息
            std::string insert_query="INSERT INTO {}(sender,content) VALUES(?,?)";
            //std::string insert_friend="INSERT IGNORE INTO friendlist(friendoc) VALUES(?)";
            std::vector<std::string> args={"0",message};
            user_conn->executeVoid(fmt::format(insert_query,targetoc),args);
            args[0]="1";
            target_conn->executeVoid(fmt::format(insert_query,useroc),args);

            //user_conn->preExecuteVoid(insert_friend,targetoc);
            //target_conn->preExecuteVoid(insert_friend,useroc);

        }
        else//不在线则缓存到对象数据库
        {
            //判断是否存在该会话的记录表
            target_conn->preExecuteVoid("INSERT INTO chat_tmp(sender,content) VALUES(?,?)",useroc,message);
            user_conn->preExecuteVoid(fmt::format("INSERT INTO {}(sender,content) VALUES('0',?)",targetoc),message);
        }
        target_conn_set->release(target_conn);
        user_conn_set->release(user_conn);
        delete content;
    }

}

void GetFriendInfoStrategy::execute(const int socket,const rapidjson::Document* content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("targetoc"))
    {
        std::string targetoc=(*content)["targetoc"].GetString();

        auto user_conn_set=SqlSetManager::getInstance()->getSet("user");
        auto user_conn=user_conn_set->acquire();

        auto res=user_conn->preExecute("SELECT user_name,avatar_path FROM userinfo WHERE useroc=?",targetoc);
        if(!user_conn->resIsEmpty())
        {
            if(res->next())
            {
                std::string target_name=res->getString(1);
                std::string avatar_path=res->getString(2);

                MsgVector userinfo;
                userinfo.createHead("friendinfo");
                userinfo.addContent(targetoc.c_str(),false);
                userinfo.addContent(target_name.c_str(),false);

                int pre_len=userinfo.length();
                std::ifstream ios(avatar_path,std::ios::binary);
                if(!ios)
                {
                    std::cout<<"open file failed"<<std::endl;
                    user_conn_set->release(user_conn);
                    return;
                }
                ios.seekg(0,std::ios::end);
                std::streamsize file_size=ios.tellg();
                ios.seekg(0,std::ios::beg);
                int read_done=0;
                int block_size=BLOCK_SIZE;

                userinfo.resize(pre_len+file_size+1);


                while(read_done<file_size)
                {
                    if(file_size-read_done<block_size)
                    {
                        block_size=file_size-read_done;
                    }

                    ios.read(userinfo[read_done+pre_len],block_size);
                    read_done+=block_size;
                }

                auto res_str=userinfo.getMsg();
                TcpServer::sendMsg(socket,*res_str);
                delete res_str;

            }
        }
        else
        {
            MsgVector userinfo;
            userinfo.createHead("friendnotfound");
            auto str=userinfo.getMsg();
            TcpServer::sendMsg(socket,*str);
            delete str;
        }
        user_conn_set->release(user_conn);
    }
}

void GetFriendApplyTmpStrategy::execute(const int socket, const rapidjson::Document *content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("useroc"))
    {
        std::string useroc=(*content)["useroc"].GetString();
        auto user_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));
        auto user_conn=user_conn_set->acquire();


        auto res=user_conn->execute("SELECT user.userinfo.useroc,user.userinfo.user_name,friendapply_tmp.apply_status,user.userinfo.avatar_path FROM user.userinfo INNER JOIN friendapply_tmp ON user.userinfo.useroc = friendapply_tmp.targetoc");
        while(res->next())
        {
            std::string targetoc=res->getString(1);
            std::string target_name=res->getString(2);
            std::string status=res->getString(3);
            std::string avatar=res->getString(4);

            MsgVector msg;
            msg.createHead("friendapplytmp");
            msg.addContent(targetoc.c_str(),false);
            msg.addContent(target_name.c_str(),false);
            msg.addContent(status.c_str(),false);
            int pre_len=msg.length();
            std::ifstream ios(avatar,std::ios::binary);
            if(!ios)
            {
                std::cout<<"open file failed"<<std::endl;
                user_conn_set->release(user_conn);
                return;
            }
            ios.seekg(0,std::ios::end);
            std::streamsize file_size=ios.tellg();
            ios.seekg(0,std::ios::beg);
            int read_done=0;
            int block_size=BLOCK_SIZE;

            msg.resize(pre_len+file_size+1);


            while(read_done<file_size)
            {
                if(file_size-read_done<block_size)
                {
                    block_size=file_size-read_done;
                }

                ios.read(msg[read_done+pre_len],block_size);
                read_done+=block_size;
            }

            auto str=msg.getMsg();
            TcpServer::sendMsg(socket,*str);
            delete str;
        }
        user_conn->resetResPos();
        while(res->next())
        {
            std::string oc=res->getString(1);
            std::string status=res->getString(3);

            user_conn->preExecuteVoid("INSERT INTO friendapply(targetoc,apply_status) VALUES(?,?) ON DUPLICATE KEY UPDATE targetoc=VALUES(targetoc),apply_status=VALUES(apply_status)",oc,status);
        }
        user_conn->executeVoid("TRUNCATE TABLE friendapply_tmp");
        user_conn_set->release(user_conn);
        MsgVector end;
        end.createHead("friendapplytmpend");
        auto end_str=end.getMsg();
        TcpServer::sendMsg(socket,*end_str);
        delete end_str;
    }
    delete content;
}

void GetOCUpdateStrategy::execute(const int socket, const rapidjson::Document *content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("useroc"))
    {
        std::string useroc=(*content)["useroc"].GetString();

        auto user_conn_set=SqlSetManager::getInstance()->getSet("user");
        auto user_conn=user_conn_set->acquire();


        auto res=user_conn->preExecute("SELECT oldoc,newoc,targetoc FROM ocupdate WHERE targetoc=?",useroc);
        JsonEncoder::OCUpdateJson msg;
        while(res->next())
        {
            std::string targetoc=res->getString(3);
            std::string oldoc=res->getString(1);
            std::string newoc=res->getString(2);

            auto target_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(targetoc));
            auto target_conn=target_conn_set->acquire();

            target_conn->executeVoid(fmt::format("ALTER TABLE {} RENAME TO {}",oldoc,newoc));

            msg.addContent(res->getString(1),res->getString(2));
            target_conn->preExecuteVoid("UPDATE contactlist SET useroc=? WHERE useroc=?",newoc,oldoc);
            target_conn->preExecuteVoid("UPDATE friendlist SET friendoc=? WHERE friendoc=?",newoc,oldoc);
            target_conn->preExecuteVoid("UPDATE friendapply SET targetoc=? WHERE targetoc=?",newoc,oldoc);
            target_conn->preExecuteVoid("UPDATE friendapply_tmp SET targetoc=? WHERE targetoc=?",newoc,oldoc);
            target_conn->preExecuteVoid("UPDATE chat_tmp SET sender=? WHERE sender=?",newoc,oldoc);

            target_conn_set->release(target_conn);


        }
        std::string result;
        msg.getString(result);
        TcpServer::sendMsg(socket,result);
        user_conn->preExecuteVoid("DELETE FROM ocupdate WHERE targetoc=?",useroc);
        user_conn_set->release(user_conn);
    }
}

void GetNameUpdateStrategy::execute(const int socket, const rapidjson::Document *content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("useroc"))
    {
        std::string useroc=(*content)["useroc"].GetString();

        auto userinfo_conn_set=SqlSetManager::getInstance()->getSet("user");
        auto userinfo_conn=userinfo_conn_set->acquire();

        auto nameupdate_res=userinfo_conn->preExecute("SELECT useroc,newname FROM nameupdate WHERE targetoc=?",useroc);
        JsonEncoder::NameUpdateJson msg;
        while(nameupdate_res->next())
        {
            msg.addContent(nameupdate_res->getString(1),nameupdate_res->getString(2));
        }
        std::string str;
        msg.getString(str);
        TcpServer::sendMsg(socket,str);
        userinfo_conn->preExecuteVoid("DELETE FROM nameupdate WHERE targetoc=?",useroc);
        userinfo_conn_set->release(userinfo_conn);
    }
}

void GetFriendAvatarTmpStrategy::execute(const int socket, const rapidjson::Document *content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("useroc"))
    {
        std::string useroc=(*content)["useroc"].GetString();

        auto userinfo_conn_set=SqlSetManager::getInstance()->getSet("user");
        auto userinfo_conn=userinfo_conn_set->acquire();
        auto res=userinfo_conn->preExecute("SELECT userinfo.useroc,userinfo.avatar_path FROM userinfo JOIN avatarupdate ON userinfo.useroc=avatarupdate.useroc WHERE avatarupdate.targetoc=?",useroc);
        while(res->next())
        {
            std::string oc=res->getString(1);
            std::string path=res->getString(2);

            MsgVector msg;
            msg.createHead("friendavatartmp");
            msg.addContent(oc.c_str(),false);

            int pre_len=msg.length();
            std::ifstream ios(path,std::ios::binary);
            if(!ios)
            {
                std::cout<<"open file failed"<<std::endl;
                userinfo_conn_set->release(userinfo_conn);
                return;
            }
            ios.seekg(0,std::ios::end);
            std::streamsize file_size=ios.tellg();
            ios.seekg(0,std::ios::beg);
            int read_done=0;
            int block_size=BLOCK_SIZE;

            msg.resize(pre_len+file_size+1);


            while(read_done<file_size)
            {
                if(file_size-read_done<block_size)
                {
                    block_size=file_size-read_done;
                }

                ios.read(msg[read_done+pre_len],block_size);
                read_done+=block_size;
            }
            auto str=msg.getMsg();
            TcpServer::sendMsg(socket,*str);
            delete str;
        }
        userinfo_conn->preExecuteVoid("DELETE FROM avatarupdate WHERE targetoc=?",useroc);
        userinfo_conn_set->release(userinfo_conn);
        MsgVector end;
        end.createHead("friendavatartmpend");
        auto end_str=end.getMsg();
        TcpServer::sendMsg(socket,*end_str);
        delete end_str;

    }
    delete content;
}


void GetFriendListStrategy::execute(const int socket, const rapidjson::Document *content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("useroc"))
    {
        std::string useroc=(*content)["useroc"].GetString();
        auto user_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));

        auto user_conn=user_conn_set->acquire();
        auto res=user_conn->execute("SELECT * FROM friendlist");
        MsgVector msg;
        msg.createHead("friendlist");
        while(res->next())
        {
            msg.addContent(res->getString(1).c_str(),false);
        }
        msg.eraseBack(3);
        auto str=msg.getMsg();

        TcpServer::sendMsg(socket,*str);

        delete str;
        user_conn_set->release(user_conn);
    }
    delete content;
}


void FriendApplyStrategy::execute(const int socket,const rapidjson::Document* content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }
    if(content->HasMember("targetoc")&&content->HasMember("useroc"))
    {
        std::string useroc=(*content)["useroc"].GetString();
        std::string targetoc=(*content)["targetoc"].GetString();

        //对方用户是否在线
        if(SocketManager::getInstacne()->isAlive(targetoc))
        {
            auto userinfo_conn_set=SqlSetManager::getInstance()->getSet("user");
            auto userinfo_conn=userinfo_conn_set->acquire();
            auto res=userinfo_conn->preExecute("SELECT user_name,avatar_path FROM userinfo WHERE useroc=?",useroc);
            auto target_socket=SocketManager::getInstacne()->getSocket(targetoc);
            if(!userinfo_conn->resIsEmpty()&&res->next())
            {
                std::string user_name=res->getString(1);
                std::string avatar_path=res->getString(2);

                MsgVector apply;
                apply.createHead("friendapply");
                apply.addContent(useroc.c_str(),false);
                apply.addContent(user_name.c_str(),false);

                int pre_len=apply.length();
                std::ifstream ios(avatar_path,std::ios::binary);
                if(!ios)
                {
                    std::cout<<"open file failed"<<std::endl;
                    userinfo_conn_set->release(userinfo_conn);
                    return;
                }

                ios.seekg(0,std::ios::end);
                std::streamsize file_size=ios.tellg();
                ios.seekg(0,std::ios::beg);
                int read_done=0;
                int block_size=BLOCK_SIZE;

                apply.resize(pre_len+file_size+1);


                while(read_done<file_size)
                {
                    if(file_size-read_done<block_size)
                    {
                        block_size=file_size-read_done;
                    }

                    ios.read(apply[read_done+pre_len],block_size);
                    read_done+=block_size;
                }


                auto str=apply.getMsg();
                TcpServer::sendMsg(target_socket,*str);
                delete str;


                userinfo_conn_set->release(userinfo_conn);

                auto target_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(targetoc));
                auto target_conn=target_conn_set->acquire();
                target_conn->preExecuteVoid("INSERT INTO friendapply VALUES(?,'0')",useroc);            }
        }
        else
        {
            auto target_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(targetoc));
            auto target_conn=target_conn_set->acquire();

            target_conn->preExecuteVoid("INSERT INTO friendapply_tmp VALUES(?,'0')",useroc);

            target_conn_set->release(target_conn);
        }
        auto user_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));
        auto user_conn=user_conn_set->acquire();
        user_conn->preExecuteVoid("INSERT INTO friendapply VALUES(?,'3')",targetoc);
        user_conn_set->release(user_conn);
    }
}

void FriendApplyPassStrategy::execute(const int socket,const rapidjson::Document* content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }

    if(content->HasMember("targetoc")&&content->HasMember("useroc"))
    {
        std::string targetoc=(*content)["targetoc"].GetString();
        std::string useroc=(*content)["useroc"].GetString();

        std::string create_query="CREATE TABLE {} ("
                                 "id INT PRIMARY KEY NOT NULL AUTO_INCREMENT,"
                                 "sender CHAR(1) NOT NULL,"
                                 "content VARCHAR(255) NOT NULL"
                                 ")";

        //更新用户的通讯录以及好友申请表
        auto user_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));
        auto user_conn=user_conn_set->acquire();
        user_conn->preExecuteVoid("UPDATE friendapply SET apply_status=1 WHERE targetoc=?",targetoc);
        user_conn->preExecuteVoid("INSERT INTO contactlist(useroc) VALUES(?)",targetoc);
        user_conn->executeVoid(fmt::format(create_query,targetoc));
        user_conn_set->release(user_conn);
        //目标在线
        if(SocketManager::getInstacne()->isAlive(targetoc))
        {

            auto userinfo_conn_set=SqlSetManager::getInstance()->getSet("user");
            auto userinfo_conn=userinfo_conn_set->acquire();
            //获取用户名，头像
            auto res=userinfo_conn->preExecute("SELECT user_name,avatar_path FROM userinfo WHERE useroc=?",useroc);
            if(res->next())
            {
                std::cout<<"444"<<std::endl;
                MsgVector msg;
                msg.createHead("friendapplyaccess");
                msg.addContent(useroc.c_str(),false);
                msg.addContent(res->getString(1).c_str(),false);

                int pre_len=msg.length();
                std::ifstream ios(res->getString(2),std::ios::binary);
                if(!ios)
                {
                    std::cout<<"open file failed"<<std::endl;
                    userinfo_conn_set->release(userinfo_conn);
                    return;
                }
                userinfo_conn_set->release(userinfo_conn);
                ios.seekg(0,std::ios::end);
                std::streamsize file_size=ios.tellg();
                ios.seekg(0,std::ios::beg);
                int read_done=0;
                int block_size=BLOCK_SIZE;

                msg.resize(pre_len+file_size+1);


                while(read_done<file_size)
                {
                    if(file_size-read_done<block_size)
                    {
                        block_size=file_size-read_done;
                    }

                    ios.read(msg[read_done+pre_len],block_size);
                    read_done+=block_size;
                }

                auto str=msg.getMsg();

                int target_socket=SocketManager::getInstacne()->getSocket(targetoc);
                TcpServer::sendMsg(target_socket,*str);


                delete str;
            }
            //更新目标的好友申请表
            auto target_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(targetoc));
            auto target_conn=target_conn_set->acquire();
            target_conn->preExecuteVoid("UPDATE friendapply SET apply_status='2' WHERE targetoc=?",useroc);
            target_conn->preExecuteVoid("INSERT INTO contactlist(useroc) VALUES(?)",useroc);

            target_conn->executeVoid(fmt::format(create_query,useroc));
            target_conn_set->release(target_conn);
        }
        //不在线
        else
        {
            auto target_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(targetoc));
            auto target_conn=target_conn_set->acquire();
            //缓存到好友申请缓存表中
            target_conn->preExecuteVoid("INSERT INTO friendapply_tmp VALUES(?,'2')",useroc);
            target_conn->preExecuteVoid("INSERT INTO contactlist VALUES(?)",useroc);
            target_conn_set->release(target_conn);
        }
    }
}

void UpdateUserOCStrategy::execute(const int socket,const rapidjson::Document* content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }

    if(content->HasMember("useroc")&&content->HasMember("newoc"))
    {
        std::string useroc=(*content)["useroc"].GetString();
        std::string newoc=(*content)["newoc"].GetString();

        //修改本地头像文件名
        std::string newpath="./Avatar/";
        newpath.append(newoc);
        newpath.append(".png");

        auto user_conn_set=SqlSetManager::getInstance()->getSet("user");
        auto user_conn=user_conn_set->acquire();
        auto res=user_conn->preExecute("SELECT avatar_path FROM userinfo WHERE useroc=?",useroc);
        if(res->next())
        {
            auto oldpath=res->getString(1);
            rename(oldpath.c_str(),newpath.c_str());
        }
        //更新用户信息表中useroc,avatar_path
        std::vector<std::string> arg={newoc,newpath,useroc};
        user_conn->preExecuteVoid("UPDATE userinfo SET useroc=?,avatar_path=? WHERE useroc=?",arg);
        //更新数据库名表中useroc
        user_conn->preExecuteVoid("UPDATE dbinfo SET useroc=? WHERE useroc=?",newoc,useroc);

        user_conn->preExecuteVoid("UPDATE avatarupdate SET useroc=? WHERE useroc=?",newoc,useroc);

        user_conn->preExecuteVoid("UPDATE nameupdate SET useroc=? WHERE useroc=?",newoc,useroc);


        //更新缓冲区
        OCDatabaseMapper::getInstance()->updateOC(useroc,newoc);
        SocketManager::getInstacne()->updateOC(useroc,newoc);

        auto broadcast_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(newoc));
        auto broadcast_conn=broadcast_conn_set->acquire();
        auto friend_res=broadcast_conn->execute("SELECT useroc AS value FROM contactlist UNION SELECT targetoc AS value FROM friendapply WHERE apply_status='0' OR apply_status='3'");
        std::string msg;
        JsonEncoder::getInstance().updateFriendOC(msg,useroc,newoc);
        while(friend_res->next())
        {
            std::string targetoc=friend_res->getString(1);

            if(SocketManager::getInstacne()->isAlive(targetoc))
            {

                auto target_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(targetoc));
                auto target_conn=target_conn_set->acquire();

                auto table_res=target_conn->execute(fmt::format("SHOW TABLES LIKE '{}'",useroc));

                if(table_res->next())
                    target_conn->executeVoid(fmt::format("ALTER TABLE {} RENAME TO {}",useroc,newoc));

                target_conn->startTransaction();
                target_conn->preExecuteVoid("UPDATE contactlist SET useroc=? WHERE useroc=?",newoc,useroc);
                target_conn->preExecuteVoid("UPDATE friendlist SET friendoc=? WHERE friendoc=?",newoc,useroc);
                target_conn->preExecuteVoid("UPDATE friendapply SET targetoc=? WHERE targetoc=?",newoc,useroc);
                target_conn->preExecuteVoid("UPDATE friendapply_tmp SET targetoc=? WHERE targetoc=?",newoc,useroc);
                target_conn->preExecuteVoid("UPDATE chat_tmp SET sender=? WHERE sender=?",newoc,useroc);
                target_conn->commit();

                target_conn_set->release(target_conn);

                int target_socket=SocketManager::getInstacne()->getSocket(targetoc);
                TcpServer::sendMsg(target_socket,msg);
            }
            else
            {
                auto res=user_conn->preExecute("SELECT id FROM ocupdate WHERE targetoc=? AND newoc=?",targetoc,useroc);
                if(res->next())
                {
                    std::vector<std::string> args={newoc,targetoc,useroc};
                    user_conn->preExecuteVoid("UPDATE ocupdate SET newoc=? WHERE targetoc=? AND newoc=?",args);
                }
                else
                {
                    std::vector<std::string> args={targetoc,useroc,newoc};
                    user_conn->preExecuteVoid("INSERT INTO ocupdate(targetoc,oldoc,newoc) VALUES(?,?,?)",args);
                }
            }
        }
        user_conn_set->release(user_conn);
        broadcast_conn_set->release(broadcast_conn);

    }


    delete content;

}





void UpdateUserNameStrategy::execute(const int socket,const rapidjson::Document* content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }

    if(content->HasMember("useroc")&&content->HasMember("newname"))
    {
        std::string useroc=(*content)["useroc"].GetString();
        std::string newname=(*content)["newname"].GetString();

        auto userinfo_conn_set=SqlSetManager::getInstance()->getSet("user");
        auto userinfo_conn=userinfo_conn_set->acquire();
        userinfo_conn->preExecuteVoid("UPDATE userinfo SET user_name=? WHERE useroc=?",newname,useroc);
        userinfo_conn_set->release(userinfo_conn);


        auto broadcast_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));
        auto broadcast_conn=broadcast_conn_set->acquire();
        auto friend_res=broadcast_conn->execute("SELECT useroc AS value FROM contactlist UNION SELECT targetoc AS value FROM friendapply WHERE apply_status='0' OR apply_status='3'");
        while(friend_res->next())
        {
            std::string targetoc=friend_res->getString(1);
            if(SocketManager::getInstacne()->isAlive(targetoc))
            {
                int target_socket=SocketManager::getInstacne()->getSocket(targetoc);
                std::string msg;
                JsonEncoder::getInstance().updateFriendName(msg,useroc,newname);
                TcpServer::sendMsg(target_socket,msg);
            }
            else
            {
                auto userinfo_conn_set=SqlSetManager::getInstance()->getSet("user");
                auto userinfo_conn=userinfo_conn_set->acquire();
                auto res=userinfo_conn->preExecute("SELECT id FROM nameupdate WHERE targetoc=? AND useroc=?",targetoc,useroc);
                if(res->next())
                {
                    std::vector<std::string> args={newname,targetoc,useroc};
                    userinfo_conn->preExecuteVoid("UPDATE nameupdate SET newname=? WHERE targetoc=? AND useroc=?",args);
                }
                else
                {
                    std::vector<std::string> args={targetoc,useroc,newname};
                    userinfo_conn->preExecuteVoid("INSERT INTO nameupdate(targetoc,useroc,newname) VALUES(?,?,?)",args);
                }
                userinfo_conn_set->release(userinfo_conn);
            }
        }

    }
}


void AddToFriendListStrategy::execute(const int socket, const rapidjson::Document *content) const
{
    if(content->HasParseError())
    {
        delete content;
        return;
    }

    if(content->HasMember("useroc")&&content->HasMember("friendoc"))
    {
        std::string useroc=(*content)["useroc"].GetString();
        std::string friendoc=(*content)["friendoc"].GetString();

        auto user_conn_set=SqlSetManager::getInstance()->getSet(OCDatabaseMapper::getInstance()->getDB(useroc));
        auto user_conn=user_conn_set->acquire();
        user_conn->preExecuteVoid("INSERT IGNORE INTO friendlist VALUES(?)",friendoc);
        user_conn_set->release(user_conn);
    }
    delete content;
}

MsgVector::MsgVector()
{
    format="#$^";
}

void MsgVector::createHead(const char* type)
{

    msg.insert(msg.end(),format,format+strlen(format));
    msg.insert(msg.end(),type,type+strlen(type));
    msg.insert(msg.end(),format,format+strlen(format));
}

void MsgVector::addContent(const char *content,int is_end)
{
    msg.insert(msg.end(),content,content+strlen(content));
    if(!is_end)
        msg.insert(msg.end(),format,format+strlen(format));
}

void MsgVector::eraseBack(int len)
{
    for(int i=0;i<len;i++)
        msg.pop_back();
}



std::string* MsgVector::getMsg()
{
    return new std::string(msg.begin(),msg.end());
}

void MsgVector::clear()
{
    msg.clear();
}

int MsgVector::length()
{
    return msg.size();
}

void MsgVector::resize(int size)
{
    msg.resize(size);
}





